package example.demo.cas;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class CASUse {

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe /*= Unsafe.getUnsafe()*/;
    private static final long valueOffset;

    static {
        try {
            Class<Unsafe> unsafeClass = Unsafe.class;
            Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
            valueOffset = unsafe.objectFieldOffset
                    (CASUse.class.getDeclaredField("value"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    private volatile int value;

    public int valueAdd() {
        int val = value;
        int count = 0;
        while (!unsafe.compareAndSwapInt(this, valueOffset, val, val + 1)) {
            val = value;
//            if (((count = (++count) & 31)) == 0) {
//                Thread.yield();
//            }
        }
        return val + 1;
    }

    public int getValue() {
        return value;
    }

    public static void main(String[] args) throws InterruptedException {
        int count = 500;
        CountDownLatch latch = new CountDownLatch(count);
        CountDownLatch main = new CountDownLatch(count);
        CASUse casUse = new CASUse();
        for (int i = 0; i < count; i++) {
//            new Thread(casUse::valueAdd).start();
            new Thread(() -> {
//                System.out.println(Thread.currentThread().getName() + "====gogogo");
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int j = 0; j < 10000; j++) {
                    casUse.valueAdd();
                }
//                System.out.println(Thread.currentThread().getName() + "====end-end-end");
                main.countDown();
            }).start();
            latch.countDown();
        }
        long l = System.currentTimeMillis();
        main.await();
        System.out.println(System.currentTimeMillis() - l);
        System.out.println("计算结果---" + casUse.getValue());
    }
}
